package kotlin05.src.main.java.com.example.kotlin05.s02

import kotlin05.src.main.java.com.example.kotlin05.s01.easyPrint4
import java.io.File

/**
 * 8. APPLY
 * DSL ： 使用这种编程范式，就可以写出业界知名的“领域特定语言”（DSL） ,一种API编程范式，
 * 报漏接收者的函数和特性，以便于使用你定义的lambda表达式来读取和配置他们
 *
 * TODO: 牢记------>  T.() 是 this        （T）是 it
 */
fun main() {

    //正常写法1
    val file = File("xxx").apply {
        //TODO: 这里的this 就是利用了泛型的扩展函数特性返回接收者
        setReadable(true)
    }
    //将apply的参数入参步骤（泛型扩展函数） 上述写法进行分解
    //1.先定义file的扩展函数
    fun File.ext() : Unit{
        this.setReadable(true)
    }
    //2.将file定义的扩展函数赋值给block
    val block = File::ext

    //3.传入到apply函数，作为参数传入
    File("xxx").apply(block)
    //这种传入{} 里面不生效，相当于将block传入到了扩展函数里面，没有效果
//    File("xxx").apply{block}




    println(file)

    //这个是最传统的apply函数，在最初的实验中，我们可以使用它设置对象的属性，然后返回这个对象3


    //string 的扩展函数
    "asggggg".addExtt().easyPrint4()


}

//扩展函数
//给字符串添加扩展函数
//fun String.addExtt(amount:Int = 1) = this + "!".repeat(amount)
//fun String.addExtt() =  "!".repeat(count())
fun String.addExtt() = this +  "!".repeat(this.count())



//泛型的扩展函数

//fun  <T> T.easyFormat() : T {
//    println(this)
//    return this
//}
fun  <T> T.easyFormat() : Unit = println(this)


//TODO: T.() -> Unit 这里传入的就是泛型的扩展函数
//TODO: 1.为什么要传入的是一个泛型的扩展函数 T.() -> Unit，而不是一个匿名函数 () -> Unit
//TODO: 这样写法是为了保留 this指向. 扩展函数里自带了接收者队对象的this隐式调用  可以参考 下面String.addExtt()方法
//TODO: 2.为什么是泛型的扩展函数？
//TODO: 为了兼容任意类型
//TODO: 匿名函数也可以是扩展函数
//TODO: 普通的匿名函数  （）-> Unit
//TODO: 匿名函数内部this 指向一个XX对象 ，也就是隐式调用
//TODO: 例如： File.() -> Unit

/*public inline fun <T> T.apply(block: T.() -> Unit): T {
//    block()
    return this
}*/

//1.如果不用泛型的扩展函数该怎么定义apply 以File对象为例
public inline fun File.apply(block : File.() -> Unit) : File{
    block()
    return this
}

//2.如果使用泛型的扩展函数该怎么定义apply 将File对象替换为泛型 T
public inline fun <T> T.apply(block : T.() -> Unit) : T{
    block()
    return this
}




fun dosomething(fix : () -> Unit){

}





/*
public inline fun <T> T.apply(block: T.() -> Unit): T {
//    block()
    return this
}*/
